package com.code;

import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.RandomUtils;
import org.junit.Test;

public class Encode {
	private String protocalName = "2.24";

	public Result encode(CollectTask collectTask) {
		encodeDataPart(collectTask);
		if ("编码失败".equals(collectTask.getState()))
			return Result.error("编码失败");
		encodeHeadPart(collectTask);
		return "编码成功".equals(collectTask.getState()) ? Result.okResult() : Result.error("编码失败");
	}

	private void encodeHeadPart(CollectTask collectTask) {
		StringBuffer scode = new StringBuffer();
		scode.append("EB95");
		scode.append(String.format("%02X", collectTask.getScode().length() / 2));
		scode.append(String.format("%04X", (collectTask.getTargetStation() << 6) + collectTask.getTargetGroup()));
		scode.append(String.format("%04X", (collectTask.getSourceStation() << 6) + collectTask.getSourceGroup()));
		scode.append("0000");
		scode.append("0000");
		scode.append(collectTask.getScode());
		scode.append("00");
		scode.append(String.format("%04X", RandomUtils.nextInt(1, 65533)));
		scode.append(String.format("%04X", ByteUtil.buildCrc16(scode.toString())));
		collectTask.setScode(scode.toString());
	}

	private void encodeDataPart(CollectTask collectTask) {

		int dtype = collectTask.getDtype();
		StringBuffer scode = new StringBuffer();
		scode.append(String.format("%02X", dtype));
		scode.append(String.format("%02X", collectTask.getProject()));
		scode.append(String.format("%04X", collectTask.getEcode()));
		List<CollectParam> collectParams = collectTask.getCollectParams();

		if (collectParams != null && !collectParams.isEmpty()) {
			try {
				switch (dtype) {
				case 0x01:
					encodeSetPropertyParams(collectTask);
					break;
				case 0x02:
					break;
				case 0x03:
					encodeCommandParams(collectTask);
					break;
				case 0x04:
					encodeCommandParams(collectTask);
					break;
				case 0x06:
					encodeCommandParams(collectTask);
					break;
				case 0x0A:
					encodeCommandParams(collectTask);
					break;
				case 0x11:
					break;

				case 0x21:
					encodeSetPropertyParams(collectTask);
					break;
				case 0x31:
					/* encodeEntityParams(collectTask); */break;
				case 0x32:
					encodeCommandParams(collectTask);
					break;
				case 0x33:
					encodeCommandParams(collectTask);
					break;
				case 0x34:
					encodeCommandParams(collectTask);
					break;
				case 0x35:
					/* encodeSetComplexParams(collectTask); */break;
				case 0x60:
					encodeCommandParams(collectTask);
					break;
				default: {
					collectTask.setState("编码失败");
					collectTask.setResult(String.format("%s无法解析任务类型[%d]", protocalName, dtype));
				}
				}
			} catch (Exception e) {
				collectTask.setState("编码失败");
				collectTask.setResult(String.format("%s无法解析任务类型[%d]", protocalName, dtype));
			}
			if ("编码失败".equals(collectTask.getState()))
				return;
			switch (dtype) {
			case 0x33:
			case 0x34:
			case 0x35: {
				scode.append(String.format("%02X", collectTask.getPcode()));
				for (CollectParam collectParam : collectParams) {
					scode.append(collectParam.getPdata());
				}
				break;
			}
			default: {
				for (CollectParam collectParam : collectParams) {

					scode.append(String.format("%02X", collectParam.getPcode()));
					if (collectParam.getPdata() != null) {
						scode.append(collectParam.getPdata());
					}
				}
			}
			}

		}
		collectTask.setScode(scode.toString());
		collectTask.setState("编码成功");

	}

	private void encodeSetPropertyParams(CollectTask collectTask) throws Exception {
		int pcode;
		List<CollectParam> collectParams = collectTask.getCollectParams();
		CollectParam collectParam;
		pcode = collectParams.get(0).getPcode();
		if (pcode != 1) {
			collectTask.setState("编码失败");
			collectTask.setResult(String.format("%s要求参数设置命令以大小类编码作为开头", protocalName));
			return;
		}
		collectParam = collectParams.get(0);
		collectParam.setPdata(String.format("%02X", Integer.parseInt(collectParam.getPvalue())));

		pcode = collectParams.get(1).getPcode();
		if (pcode != 2) {
			collectTask.setState("编码失败");
			collectTask.setResult(String.format("%s要求参数设置命令以大小类编码作为开头", protocalName));
			return;
		}
		collectParam = collectParams.get(1);
		collectParam.setPdata(String.format("%02X", Integer.parseInt(collectParam.getPvalue())));
		EntityType et = JsonToJavabean.entityTypeByCode(collectTask.getMcode(), collectTask.getTcode());
		for (int i = 2; i < collectParams.size(); i++) {
			collectParam = collectParams.get(i);
			pcode = collectParam.getPcode();
			PropertyDefinition pd = getPropertyDefinition(et, pcode);
			pd.setValue(collectParam.getPvalue());
			if (pcode == 0xF4) {
				collectParam.setPvalue(DateTimeUtil.YYYYMMddHHmmss().format(new Date()));
			}
			try {
				String vtype = pd.getVtype();
				String pdata = switchValue(vtype, pd);
				collectParam.setPdata(pdata);
			} catch (Exception e) {
				collectTask.setState("编码失败");
				collectTask.setResult(String.format("大类编码为[%s]，小类编码为[%s]的对象类型[%s]中编码为[%d]的参数[%s] %s", et.getMcode(),
						et.getCode(), et.getName(), pcode, pd.getName(), e.getMessage()));
				break;

			}
		}

	}

	private PropertyDefinition getPropertyDefinition(EntityType entityType, int pcode) {
		List<PropertyDefinition> propertyDefinitions = entityType.getPropertyDefinitions();
		for (PropertyDefinition propertyDefinition : propertyDefinitions) {
			if (propertyDefinition.getCode() == pcode) {
				return propertyDefinition;
			}
		}
		return null;

	}

	private String switchValue(String vtype, PropertyDefinition propertyDefinition) throws Exception {
		String value;
		switch (vtype) {
		case ValueType.INTEGER:
			value = PropertyBuilder.IntegerBuilder.encode(propertyDefinition.getValue(),
					propertyDefinition.getDataLength());
			return value;
		case ValueType.DOUBLE:
			value = PropertyBuilder.FloatBuilder.encode(propertyDefinition.getValue(),
					propertyDefinition.getDataLength());
			return value;
		case ValueType.BOOLEAN:
			value = PropertyBuilder.BooleanBuilder.encode(propertyDefinition.getValue(),
					propertyDefinition.getDataLength());
			return value;
		case ValueType.STRING:
			value = PropertyBuilder.AscBuilder.encode(propertyDefinition.getValue(),
					propertyDefinition.getDataLength());
			return value;
		case ValueType.TIME:
			value = PropertyBuilder.TimeBuilder.encode(propertyDefinition.getValue(),
					propertyDefinition.getDataLength());
			return value;
		case ValueType.DATETIME:
			value = PropertyBuilder.DatetimeBuilder.encode(propertyDefinition.getValue(),
					propertyDefinition.getDataLength());
			return value;
		default:
			value = propertyDefinition.getValue();
			return value;
		}
	}

	private void encodeCommandParams(CollectTask collectTask) throws Exception {

		int pcode;
		PropertyDefinition pd;
		List<CollectParam> collectParams = collectTask.getCollectParams();
		for (CollectParam collectParam : collectParams) {
			pd = JsonToJavabean.commandParamByCode(collectParam.getPcode());

			if (pd == null) {
				collectTask.setState("编码失败");
				collectTask.setResult(
						String.format("无法知识查询器中取得[%s]命令中名称为[%s]参数定义", collectTask.getDname(), collectParam.getPname()));
				break;
			}
			collectParam.setPcode(pd.getCode());
			pcode = collectParam.getPcode();
			if (pd.getDataLength() == 0) {
				collectParam.setPdata("");
			} else {
				if (pcode == 0xF4) {
					Calendar cal = Calendar.getInstance();
					cal.add(Calendar.SECOND, 0);
					collectParam.setPvalue(DateTimeUtil.YYYYMMddHHmmss().format(cal.getTime()));
				}
				pd.setValue(collectParam.getPvalue());
				collectParam.setPdata(switchValue(pd.getVtype(), pd));
			}

		}

	}
	@Test
	public  void test() {

	/*	Encode encode = new Encode();
		CollectTask collectTask = new CollectTask();
		collectTask.setDtype(0x01);
		collectTask.setEcode(65533);
		collectTask.setProject(66);
		collectTask.setSourceGroup(1);
		collectTask.setSourceStation(1);
		collectTask.setMcode(8);
		collectTask.setTcode(1);
		collectTask.setTargetGroup(1);
		collectTask.setTargetStation(70);
		List<CollectParam> collectParams = new ArrayList<CollectParam>();
		CollectParam collectParam1 = new CollectParam();
		collectParam1.setPcode(1);
		collectParam1.setPvalue("8");
		collectParams.add(collectParam1);
		CollectParam collectParam2 = new CollectParam();
		collectParam2.setPcode(2);
		collectParam2.setPvalue("1");
		collectParams.add(collectParam2);
		collectTask.setCollectParams(collectParams);
		CollectParam collectParam = new CollectParam();
		collectParam.setPcode(17);
		collectParam.setPvalue("0.0");

		collectParams.add(collectParam);
		encode.encode(collectTask);*/
		//EB950D11810041000000000142FFFD01080201110000000000B36A66D8
		//EB950D11810041000000000142FFFD01080201110000000000863E7077
		Encode encode = new Encode();
		CollectTask collectTask = new CollectTask();
		collectTask.setDtype(0x33);
		collectTask.setEcode(65534);
		collectTask.setProject(66);
		collectTask.setSourceGroup(1);
		collectTask.setSourceStation(1);
		collectTask.setTargetGroup(1);
		collectTask.setTargetStation(70);
		encode.encode(collectTask);
		//EB950411810041000000003342FFFE00AE3BF194
		//EB950411810041000000003342FFFE00BC2CBD3A 
	}
}
